/**
 * 
 */
package ro.dta.idbi.ui;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;

import org.postgresql.jdbc3.Jdbc3ResultSet;

import ro.dta.idbi.interfaces.ui.IMainFrame;
import ro.dta.idbi.model.dynamicpattern.Transaction;
import uk.ac.ic.doc.automed.DSR;
import uk.ac.ic.doc.automed.DSRException;

/**
 * User interface for the transaction history dialog
 * 
 * @author Tudor Dobrila
 * 
 */
public class TransactionHistoryDialog extends JDialog {

	private static final long serialVersionUID = -9142776056125564828L;

	/**
	 * Hashcode used to filter the results
	 */
	private String hashCode;

	/**
	 * Parent frame of the application
	 */
	private final IMainFrame parentFrame;
	
	/**
	 * Table holding the results
	 */
	private AbstractTable table;
	
	/**
	 * Center panel holding all components
	 */
	private final JPanel mainPanel;
	
	/**
	 * Hash text field, used to filter the results
	 */
	private final JTextField hashField;
	
	/**
	 * Transaction history dialog class constructor
	 * 
	 * @param parentFrame
	 *            Parent frame of the application
	 */
	private TransactionHistoryDialog(IMainFrame parentFrame) {
		super();
		this.parentFrame = parentFrame;
		setSize(800, 600);
		setModal(true);
		setTitle("Transaction history browser");
		setLocationRelativeTo(null);
		setIconImage(parentFrame.getIconImage());

		mainPanel = new JGradientPanel(new GridBagLayout());
		getContentPane().add(mainPanel, BorderLayout.CENTER);
		
		hashField = new JTextField();
	}

	/**
	 * Transaction history dialog class constructor
	 * 
	 * @param parentFrame
	 *            Parent frame of the application
	 * @param transactionIds
	 *            Initial transactions to show in the dialog box
	 */
	public TransactionHistoryDialog(IMainFrame parentFrame, List<Integer> transactionIds) throws DSRException, ClassNotFoundException, IOException, SQLException {
		this(parentFrame);
		setTitle("Similar transactions from the transaction history");
		
		table = new TransactionTable(transactionIds);
		addTable(0);
	}

	/**
	 * Transaction history dialog class constructor
	 * 
	 * @param parentFrame
	 *            Parent frame of the application
	 * @param hashCode
	 *            Hash code for which to retrieve the transaction history
	 */
	public TransactionHistoryDialog(IMainFrame parentFrame, String hashCode) {
		this(parentFrame);
		this.hashCode = hashCode;
		
		GridBagConstraints constr = new GridBagConstraints();
		constr.fill = GridBagConstraints.BOTH;

		constr.ipady = 20;
		constr.gridwidth = 3;
		constr.gridx = 0;
		constr.gridy = 0;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		mainPanel.add(parentFrame.getGuiFactory().createTitleLabel("Filter transactions"), constr);

		constr.insets = new Insets(5, 0, 0, 0);
		constr.ipady = 0;
		constr.ipadx = 10;
		constr.gridwidth = 1;
		constr.gridx = 0;
		constr.gridy = 1;
		constr.weightx = 0.0;
		constr.weighty = 0.0;
		mainPanel.add(new JLabel("Hash code:"), constr);

		constr.gridx = 1;
		constr.gridy = 1;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		mainPanel.add(hashField, constr);

		constr.gridx = 2;
		constr.gridy = 1;
		constr.weightx = 0.0;
		constr.weighty = 0.0;
		JButton filterBtn = new JButton("Filter results");
		filterBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				String newHash = hashField.getText();
				TransactionHistoryDialog.this.hashCode = newHash;
				table.resetOffset();
			}
		});
		mainPanel.add(filterBtn, constr);
		
		hashField.setText(hashCode);
		table = new TransactionTable();
		table.fillTable();
		addTable(3);
	}
	
	/**
	 * Add the table to the center panel
	 */
	private void addTable(int row) {
		GridBagConstraints constr = new GridBagConstraints();
		constr.fill = GridBagConstraints.BOTH;
		constr.gridwidth = 3;
		constr.gridx = 0;
		constr.gridy = row;
		constr.weightx = 1.0;
		constr.weighty = 1.0;
		mainPanel.add(table, constr);
	}

	/**
	 * Transactions table, holding the transactions stored in the AutoMed
	 * repository
	 * 
	 * @author Tudor Dobrila
	 * 
	 */
	class TransactionTable extends AbstractTable {

		private static final long serialVersionUID = -6859626621373881620L;

		/**
		 * Transaction table class constructor
		 */
		public TransactionTable() {
			super();

			resultModel.setColumnCount(6);
			resultModel.setColumnIdentifiers(new String[] { "TID", "Instructions", "Hashcode",
					"Signature", "Original schema", "Resulting schema" });
			resultsTable.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseReleased(MouseEvent e) {
					if (e.getButton() == MouseEvent.BUTTON3 && e.getClickCount() == 1) {
						final int row = resultsTable.rowAtPoint(e.getPoint());
						final int column = resultsTable.columnAtPoint(e.getPoint());

						if (!resultsTable.isRowSelected(row)) {
							resultsTable.changeSelection(row, column, false, false);
						}

						JPopupMenu popupMenu = new JPopupMenu();
						JMenuItem item = new JMenuItem("Open transaction viewer");
						item.addActionListener(new ActionListener() {

							@Override
							public void actionPerformed(ActionEvent e) {
								// Open
								int transactionId = Integer.parseInt(resultModel.getValueAt(row, 0)
										.toString());
								Transaction trans;
								try {
									trans = Transaction.loadTransaction(transactionId);
									TransactionViewerDialog transViewer = new TransactionViewerDialog(
											parentFrame, trans);
									transViewer.setVisible(true);
								} catch (Exception e1) {
									JOptionPane.showMessageDialog(TransactionHistoryDialog.this,
											"Could not retrieve transaction with TID = "
													+ transactionId
													+ " from the AutoMed repository. Reason:\r\n"
													+ e1.getMessage(), "Error!",
											JOptionPane.ERROR_MESSAGE);
								}

							}
						});
						popupMenu.add(item);
						popupMenu.show(resultsTable, e.getX(), e.getY());
					}
				}
			});
		}

		/**
		 * Transaction table class constructors
		 * 
		 * @param initialTrans
		 *            Initial transactions displayed in the table
		 */
		public TransactionTable(List<Integer> initialTrans) throws DSRException,
				ClassNotFoundException, IOException, SQLException {
			this();

			resultModel.setRowCount(initialTrans.size());
			int crtRow = 0;
			for (Integer id : initialTrans) {
				Transaction t = Transaction.loadTransaction(id);
				resultModel.setValueAt(t.getTid(), crtRow, 0);
				StringBuilder builder = new StringBuilder();
				String[] instructions = t.getInstructions();
				for (String instr : instructions) {
					builder.append(instr).append("\n");
				}
				resultModel.setValueAt(builder.toString(), crtRow, 1);
				resultModel.setValueAt(t.getHashCode(), crtRow, 2);
				resultModel.setValueAt(t.getSignature(), crtRow, 3);
				resultModel.setValueAt(t.getOriginalSchema(), crtRow, 4);
				resultModel.setValueAt(t.getFinalSchema(), crtRow, 5);
				crtRow++;
			}
			
			toolBar.setVisible(false);
		}

		@Override
		public int getTotalResults() {
			String queryTotal = "SELECT COALESCE(COUNT(tid),0) FROM transaction";
			if (hashCode != null && !"".equals(hashCode)) {
				queryTotal += " WHERE hashcode = '" + hashCode + "'";
			}

			try {
				Jdbc3ResultSet resTotal = (Jdbc3ResultSet) DSR.executeStatement("STR", queryTotal,
						false);
				if (resTotal.next()) {
					return resTotal.getInt(1);
				}
			} catch (Exception e1) {
				JOptionPane.showMessageDialog(this,
						"Could not retrieve the total number of elements from the AutoMed repository. Reason:\r\n"
								+ e1.getMessage(), "Error!", JOptionPane.ERROR_MESSAGE);
				return -1;
			}

			return 0;
		}

		@Override
		public int getCurrentResults() {
			String queryCount = "SELECT COALESCE(COUNT(tid),0) FROM (SELECT tid FROM transaction";
			if (hashCode != null && !"".equals(hashCode)) {
				queryCount += " WHERE hashcode = '" + hashCode + "'";
			}
			queryCount += " ORDER BY tid LIMIT " + resultsShown + " OFFSET " + currentOffset
					+ ") countTable";

			resultsCount = 0;
			try {
				Jdbc3ResultSet resCount = (Jdbc3ResultSet) DSR.executeStatement("STR", queryCount,
						false);
				if (resCount.next()) {
					return resCount.getInt(1);
				}
			} catch (Exception e1) {
				JOptionPane.showMessageDialog(this,
						"Could not retrieve the total number of elements from the AutoMed repository. Reason:\r\n"
								+ e1.getMessage(), "Error!", JOptionPane.ERROR_MESSAGE);
				return -1;
			}

			return 0;
		}

		@Override
		public void refreshTable() {
			super.refreshTable();
			
			// Construct query
			String query = "SELECT * FROM transaction";
			if (hashCode != null && !"".equals(hashCode)) {
				query += " WHERE hashcode = '" + hashCode + "'";
			}
			query += " ORDER BY tid LIMIT " + resultsShown + " OFFSET " + currentOffset;

			// Execute query and update results table
			try {
				Jdbc3ResultSet result = (Jdbc3ResultSet) DSR.executeStatement("STR", query, false);
				int crtRow = 0;

				while (result.next()) {
					resultModel.setValueAt(result.getInt(1), crtRow, 0);
					resultModel.setValueAt(result.getString(2), crtRow, 1);
					resultModel.setValueAt(result.getString(3), crtRow, 2);
					resultModel.setValueAt(result.getString(4), crtRow, 3);
					resultModel.setValueAt(result.getString(5), crtRow, 4);
					resultModel.setValueAt(result.getString(6), crtRow, 5);
					crtRow++;
				}
			} catch (Exception e) {
				JOptionPane.showMessageDialog(this,
						"Could not retrieve transaction history from the AutoMed repository. Reason:\r\n"
								+ e.getMessage(), "Error!", JOptionPane.ERROR_MESSAGE);
				return;
			}
		}

	}
}
